#include "SystemSDL_1_3.h"

#include "..\..\Point.h"
#include "..\..\Color.h"
#include "..\..\Rect.h"

#include <SDL.h>

SDL_Renderer* CSystemSDL_1_3_Renderer::m_hCurrentRenderer       = NULL;

int CSystemSDL_1_3_Renderer::SetRenderColor( unsigned char red, unsigned char green,
                                             unsigned char blue, unsigned char alpha )
{
    return SDL_SetRenderDrawColor( m_hCurrentRenderer, red, green, blue, alpha );
}

int CSystemSDL_1_3_Renderer::SetRenderColor( const CColor& color )
{
    return SetRenderColor( color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha() );
}

int CSystemSDL_1_3_Renderer::DrawPoint( const CPoint& pt )
{
    SDL_assert( m_hCurrentRenderer );

    return SDL_RenderDrawPoint( m_hCurrentRenderer, pt.GetX(), pt.GetY() );
}

int CSystemSDL_1_3_Renderer::DrawPoint( const CPoint& pt, const CColor& color )
{
    SDL_assert( m_hCurrentRenderer );

    SDL_SetRenderDrawColor( m_hCurrentRenderer, color.GetRed(), color.GetGreen(),
                            color.GetBlue(), color.GetAlpha() );

    return SDL_RenderDrawPoint( m_hCurrentRenderer, pt.GetX(), pt.GetY() );
}

int CSystemSDL_1_3_Renderer::DrawPoints( const CPoint* ppts, int count )
{
    SDL_assert( m_hCurrentRenderer );

    const void* ptr = SDL_static_cast( const void*, ppts );

    return SDL_RenderDrawPoints( m_hCurrentRenderer, SDL_static_cast( const SDL_Point*, ptr ), count );
}

int CSystemSDL_1_3_Renderer::DrawPoints( const CPoint* ppts, int count, const CColor& color )
{
    SDL_assert( m_hCurrentRenderer );

    const void* ptr = SDL_static_cast( const void*, ppts );
    SDL_SetRenderDrawColor( m_hCurrentRenderer, color.GetRed(), color.GetGreen(),
                            color.GetBlue(), color.GetAlpha() );

    return SDL_RenderDrawPoints( m_hCurrentRenderer, SDL_static_cast(
                                const SDL_Point*, ptr ), count );
}

int CSystemSDL_1_3_Renderer::Draw4Points( const CPoint& origin, int dx, int dy )
{
    SDL_assert( m_hCurrentRenderer );

    int x = origin.GetX();
    int y = origin.GetY();

    SDL_Point points[4] =
    {
        //       0                   1
        { x + dx, y + dy }, { x - dx, y + dy },
        //       2                   3
        { x - dx, y - dy }, { x + dx, y - dy }
    };

    return SDL_RenderDrawPoints( m_hCurrentRenderer, points, 8 );
}

int CSystemSDL_1_3_Renderer::Draw4Points( const CPoint& origin, int dx, int dy, const CColor& color )
{
    SDL_assert( m_hCurrentRenderer );

    int x = origin.GetX();
    int y = origin.GetY();

    SDL_Point points[4] =
    {
        //       0                   1
        { x + dx, y + dy }, { x - dx, y + dy },
        //       2                   3
        { x - dx, y - dy }, { x + dx, y - dy }
    };

    SDL_SetRenderDrawColor( m_hCurrentRenderer, color.GetRed(), color.GetGreen(),
                            color.GetBlue(), color.GetAlpha() );

    return SDL_RenderDrawPoints( m_hCurrentRenderer, points, 8 );
}

int CSystemSDL_1_3_Renderer::Draw8Points( const CPoint& origin, int dx, int dy )
{
    SDL_assert( m_hCurrentRenderer );

    int x = origin.GetX();
    int y = origin.GetY();

    SDL_Point points[8] =
    {
        //       0                   1                   2                   3
        { x + dx, y + dy }, { x - dx, y + dy }, { x + dx, y - dy }, { x - dx, y - dy },
        //       4                   5                   6                   7
        { x + dy, y + dx }, { x - dy, y + dx }, { x + dy, y - dx }, { x - dy, y - dx }
    };

    return SDL_RenderDrawPoints( m_hCurrentRenderer, points, 8 );
}

int CSystemSDL_1_3_Renderer::Draw8Points( const CPoint& origin, int dx, int dy, const CColor& color )
{
    SDL_assert( m_hCurrentRenderer );

    int x = origin.GetX();
    int y = origin.GetY();

    SDL_Point points[8] =
    {
        //       0                   1                   2                   3
        { x + dx, y + dy }, { x - dx, y + dy }, { x + dx, y - dy }, { x - dx, y - dy },
        //       4                   5                   6                   7
        { x + dy, y + dx }, { x - dy, y + dx }, { x + dy, y - dx }, { x - dy, y - dx }
    };

    SDL_SetRenderDrawColor( m_hCurrentRenderer, color.GetRed(), color.GetGreen(),
                            color.GetBlue(), color.GetAlpha() );

    return SDL_RenderDrawPoints( m_hCurrentRenderer, points, 8 );
}

int CSystemSDL_1_3_Renderer::DrawLine( const CPoint& begin, const CPoint& end )
{
    SDL_assert( m_hCurrentRenderer );

    return SDL_RenderDrawLine( m_hCurrentRenderer, begin.GetX(), begin.GetY(), end.GetX(),
                               end.GetY() );
}

int CSystemSDL_1_3_Renderer::DrawLine( const CPoint& begin, const CPoint& end, const CColor& color )
{
    SDL_assert( m_hCurrentRenderer );

    SDL_SetRenderDrawColor( m_hCurrentRenderer, color.GetRed(), color.GetGreen(),
                            color.GetBlue(), color.GetAlpha() );

    return SDL_RenderDrawLine( m_hCurrentRenderer, begin.GetX(), begin.GetY(),
                               end.GetX(), end.GetY() );
}

int CSystemSDL_1_3_Renderer::Draw4Lines( const CPoint& origin, int dx, int dy, const CColor& color )
{
    SDL_assert( m_hCurrentRenderer );

    int x = origin.GetX();
    int y = origin.GetY();

    SDL_Point points[4] =
    {
        //       0                   1
        { x + dx, y + dy }, { x - dx, y + dy },
        //       2                   3
        { x - dx, y - dy }, { x + dx, y - dy }
    };

    SDL_SetRenderDrawColor( m_hCurrentRenderer, color.GetRed(), color.GetGreen(),
                            color.GetBlue(), color.GetAlpha() );

    return SDL_RenderDrawLines( m_hCurrentRenderer, points, 4 );
}

int CSystemSDL_1_3_Renderer::Draw4Lines( const CPoint& origin, int dx, int dy )
{
    SDL_assert( m_hCurrentRenderer );

    int x = origin.GetX();
    int y = origin.GetY();

    SDL_Point points[4] =
    {
        //       0                   1
        { x + dx, y + dy }, { x - dx, y + dy },
        //       2                   3
        { x - dx, y - dy }, { x + dx, y - dy }
    };

    return SDL_RenderDrawLines( m_hCurrentRenderer, points, 4 );
}

int CSystemSDL_1_3_Renderer::Draw8Lines( const CPoint& origin, int dx, int dy )
{
    SDL_assert( m_hCurrentRenderer );

    int x = origin.GetX();
    int y = origin.GetY();

    SDL_Point points[8] =
    {
        //       0                   1                   2                   3
        { x + dx, y + dy }, { x - dx, y + dy }, { x + dx, y - dy }, { x - dx, y - dy },
        //       4                   5                   6                   7
        { x + dy, y + dx }, { x - dy, y + dx }, { x + dy, y - dx }, { x - dy, y - dx }
    };

    return SDL_RenderDrawLines( m_hCurrentRenderer, points, 8 );
}

int CSystemSDL_1_3_Renderer::Draw8Lines( const CPoint& origin, int dx, int dy, const CColor& color )
{
    SDL_assert( m_hCurrentRenderer );

    int x = origin.GetX();
    int y = origin.GetY();

    SDL_Point points[8] =
    {
        //       0                   1                   2                   3
        { x + dx, y + dy }, { x - dx, y + dy }, { x + dx, y - dy }, { x - dx, y - dy },
        //       4                   5                   6                   7
        { x + dy, y + dx }, { x - dy, y + dx }, { x + dy, y - dx }, { x - dy, y - dx }
    };

    SDL_SetRenderDrawColor( m_hCurrentRenderer, color.GetRed(), color.GetGreen(),
                            color.GetBlue(), color.GetAlpha() );

    return SDL_RenderDrawLines( m_hCurrentRenderer, points, 8 );
}

int CSystemSDL_1_3_Renderer::DrawLines( const CPoint* ppts, int count )
{
    SDL_assert( m_hCurrentRenderer );

    const void* ptr = SDL_static_cast( const void*, ppts );


    return SDL_RenderDrawLines( m_hCurrentRenderer, SDL_static_cast( const SDL_Point*, ptr ), count );
}

int CSystemSDL_1_3_Renderer::DrawLines( const CPoint* ppts, int count, const CColor& color )
{
    SDL_assert( m_hCurrentRenderer );

    const void* ptr = SDL_static_cast( const void*, ppts );
    SDL_SetRenderDrawColor( m_hCurrentRenderer, color.GetRed(), color.GetGreen(),
                            color.GetBlue(), color.GetAlpha() );

    return SDL_RenderDrawLines( m_hCurrentRenderer, SDL_static_cast(
                                const SDL_Point*, ptr ), count );
}

int CSystemSDL_1_3_Renderer::DrawRect( const CRect& rect )
{
    SDL_assert( m_hCurrentRenderer );

    const void* ptr = SDL_static_cast( const void*, &rect );

    return SDL_RenderDrawRect( m_hCurrentRenderer, SDL_static_cast( const SDL_Rect*, ptr ) );
}

int CSystemSDL_1_3_Renderer::DrawRect( const CRect& rect, const CColor& color )
{
    SDL_assert( m_hCurrentRenderer );
    SDL_SetRenderDrawColor( m_hCurrentRenderer, color.GetRed(), color.GetGreen(), color.GetBlue(),
                            color.GetAlpha() );

    const void* ptr = SDL_static_cast( const void*, &rect );

    return SDL_RenderDrawRect( m_hCurrentRenderer, SDL_static_cast( const SDL_Rect*, ptr ) );
}

int CSystemSDL_1_3_Renderer::DrawRects( const CRect* rects, int count )
{
    SDL_assert( m_hCurrentRenderer );

    const void* ptr = SDL_static_cast( const void*, rects );

    return SDL_RenderDrawRects( m_hCurrentRenderer, SDL_static_cast( const SDL_Rect*, ptr ), count );
}

int CSystemSDL_1_3_Renderer::DrawRects( const CRect* prects, int count, const CColor& color )
{
    SDL_assert( m_hCurrentRenderer );

    const void* ptr = SDL_static_cast( const void*, prects );
    SDL_SetRenderDrawColor( m_hCurrentRenderer, color.GetRed(), color.GetGreen(),
                            color.GetBlue(), color.GetAlpha() );

    return SDL_RenderDrawRects( m_hCurrentRenderer, SDL_static_cast( const SDL_Rect*, ptr ), count );
}

int CSystemRenderer::DrawFilledRect( const CRect& rect )
{
    SDL_assert( m_hCurrentRenderer );

    const void* ptr = SDL_static_cast( const void*, &rect );

    return SDL_RenderFillRect( m_hCurrentRenderer, SDL_static_cast( const SDL_Rect*, ptr ) );
}

int CSystemSDL_1_3_Renderer::DrawFilledRect( const CRect& rect, const CColor& color )
{
    SDL_assert( m_hCurrentRenderer );

    const void* ptr = SDL_static_cast( const void*, &rect );
    SDL_SetRenderDrawColor( m_hCurrentRenderer, color.GetRed(), color.GetGreen(),
                            color.GetBlue(), color.GetAlpha() );

    return SDL_RenderFillRect( m_hCurrentRenderer, SDL_static_cast( const SDL_Rect*, ptr ) );
}

int CSystemSDL_1_3_Renderer::DrawFilledRects( const CRect* prects, int count )
{
    SDL_assert( m_hCurrentRenderer );

    const void* ptr = SDL_static_cast( const void*, prects );

    return SDL_RenderFillRects( m_hCurrentRenderer, SDL_static_cast( const SDL_Rect*, ptr ), count );
}

int CSystemSDL_1_3_Renderer::DrawFilledRects( const CRect* prects, int count, const CColor& color )
{
    SDL_assert( m_hCurrentRenderer );

    const void* ptr = SDL_static_cast( const void*, prects );
    SDL_SetRenderDrawColor( m_hCurrentRenderer, color.GetRed(), color.GetGreen(),
                            color.GetBlue(), color.GetAlpha() );

    return SDL_RenderFillRects( m_hCurrentRenderer, SDL_static_cast( const SDL_Rect*, ptr ), count );
}

int CSystemSDL_1_3_Renderer::DrawEllipse( const CPoint& origin, int radius )
{
    // http://homepage.smc.edu/kennedy_john/belipse.pdf
    int x = radius;
    int y = 0;
    int ee = 0;
    int twoAsq = 2 * radius * radius;
    int twoBsq = 2 * radius * radius;
    int xChange = radius * radius * ( 1 - 2 * radius );
    int yChange = radius * radius;
    int ret = 0;
    int stoppingX = twoBsq * radius;
    int stoppingY = 0;

    while( stoppingX >= stoppingY )
    {
        Draw4Points( origin, x, y );
        ++y;
        stoppingY += twoAsq;
        ee += yChange;
        yChange += twoAsq;

        if( ( 2 * ee + xChange ) > 0 )
        {
            --x;
            stoppingX -= twoBsq;
            ee += xChange;
            xChange += twoBsq;
        }
    }

    x = 0;
    y = radius;
    xChange = radius * radius;
    yChange = radius * radius * ( 1 - 2 * radius );
    ee = 0;
    stoppingX = 0;
    stoppingY = twoAsq * radius;

    while( stoppingX <= stoppingY )
    {
        Draw4Points( origin, x, y );
        ++x;
        stoppingX += twoBsq;
        ee += xChange;
        xChange += twoBsq;

        if( ( 2 * ee + yChange ) > 0 )
        {
            --y;
            stoppingY -= twoAsq;
            ee += yChange;
            yChange += twoAsq;
        }
    }

    return ret;
}

int CSystemSDL_1_3_Renderer::DrawEllipse( const CPoint& origin, int radius, const CColor& color )
{
    // http://homepage.smc.edu/kennedy_john/belipse.pdf
    int x = radius;
    int y = 0;
    int ee = 0;
    int twoAsq = 2 * radius * radius;
    int twoBsq = 2 * radius * radius;
    int xChange = radius * radius * ( 1 - 2 * radius );
    int yChange = radius * radius;
    int ret = 0;
    int stoppingX = twoBsq * radius;
    int stoppingY = 0;

    while( stoppingX >= stoppingY )
    {
        Draw4Points( origin, x, y, color );
        ++y;
        stoppingY += twoAsq;
        ee += yChange;
        yChange += twoAsq;

        if( ( 2 * ee + xChange ) > 0 )
        {
            --x;
            stoppingX -= twoBsq;
            ee += xChange;
            xChange += twoBsq;
        }
    }

    x = 0;
    y = radius;
    xChange = radius * radius;
    yChange = radius * radius * ( 1 - 2 * radius );
    ee = 0;
    stoppingX = 0;
    stoppingY = twoAsq * radius;

    while( stoppingX <= stoppingY )
    {
        Draw4Points( origin, x, y );
        ++x;
        stoppingX += twoBsq;
        ee += xChange;
        xChange += twoBsq;

        if( ( 2 * ee + yChange ) > 0 )
        {
            --y;
            stoppingY -= twoAsq;
            ee += yChange;
            yChange += twoAsq;
        }
    }

    return ret;
}

int CSystemSDL_1_3_Renderer::DrawFilledEllipse( const CPoint& origin, int radius )
{
    // http://homepage.smc.edu/kennedy_john/belipse.pdf
    int x = radius;
    int y = 0;
    int ee = 0;
    int twoAsq = 2 * radius * radius;
    int twoBsq = 2 * radius * radius;
    int xChange = radius * radius * ( 1 - 2 * radius );
    int yChange = radius * radius;
    int ret = 0;
    int stoppingX = twoBsq * radius;
    int stoppingY = 0;

    while( stoppingX >= stoppingY )
    {
        Draw4Lines( origin, x, y );
        ++y;
        stoppingY += twoAsq;
        ee += yChange;
        yChange += twoAsq;

        if( ( 2 * ee + xChange ) > 0 )
        {
            --x;
            stoppingX -= twoBsq;
            ee += xChange;
            xChange += twoBsq;
        }
    }

    x = 0;
    y = radius;
    xChange = radius * radius;
    yChange = radius * radius * ( 1 - 2 * radius );
    ee = 0;
    stoppingX = 0;
    stoppingY = twoAsq * radius;

    while( stoppingX <= stoppingY )
    {
        Draw4Lines( origin, x, y );
        ++x;
        stoppingX += twoBsq;
        ee += xChange;
        xChange += twoBsq;

        if( ( 2 * ee + yChange ) > 0 )
        {
            --y;
            stoppingY -= twoAsq;
            ee += yChange;
            yChange += twoAsq;
        }
    }

    return ret;
}

int CSystemSDL_1_3_Renderer::DrawFilledEllipse( const CPoint& origin, int radius, const CColor& color )
{
    // http://homepage.smc.edu/kennedy_john/belipse.pdf
    int x = radius;
    int y = 0;
    int ee = 0;
    int twoAsq = 2 * radius * radius;
    int twoBsq = 2 * radius * radius;
    int xChange = radius * radius * ( 1 - 2 * radius );
    int yChange = radius * radius;
    int ret = 0;
    int stoppingX = twoBsq * radius;
    int stoppingY = 0;

    while( stoppingX >= stoppingY )
    {
        Draw4Lines( origin, x, y, color );
        ++y;
        stoppingY += twoAsq;
        ee += yChange;
        yChange += twoAsq;

        if( ( 2 * ee + xChange ) > 0 )
        {
            --x;
            stoppingX -= twoBsq;
            ee += xChange;
            xChange += twoBsq;
        }
    }

    x = 0;
    y = radius;
    xChange = radius * radius;
    yChange = radius * radius * ( 1 - 2 * radius );
    ee = 0;
    stoppingX = 0;
    stoppingY = twoAsq * radius;

    while( stoppingX <= stoppingY )
    {
        Draw4Lines( origin, x, y );
        ++x;
        stoppingX += twoBsq;
        ee += xChange;
        xChange += twoBsq;

        if( ( 2 * ee + yChange ) > 0 )
        {
            --y;
            stoppingY -= twoAsq;
            ee += yChange;
            yChange += twoAsq;
        }
    }

    return ret;
}

